﻿namespace Jiubang.Communication.Server {
    using System;
    using Collections;
    using log4net;

    /// <summary>
    /// 使用连续区域实现的定长缓冲区段。<br/>
    /// 性能较高适合于短消息交互。
    /// </summary>
    internal sealed class AlignedBuffer {
        private readonly bool[] bufferUsage;
        private readonly LockFreeStack<int> freeIndexPool;
        private readonly int size;
        private static readonly ILog log = LogManager.GetLogger(typeof(AlignedBuffer));

        public AlignedBuffer(int size, int count) {
            this.size = size;

            bufferUsage = new bool[count];
            Buffer = new byte[size * count];
            freeIndexPool = new LockFreeStack<int>();
            for (int i = count - 1; i >= 0; i--)
                freeIndexPool.Push(i * size);
        }

        public byte[] Buffer { get; private set; }
        public int Size { get { return size; } }
        public int Count { get { return bufferUsage.Length; } }

        /// <summary>
        /// 从缓冲区中获取一个偏移量。该值非负时表示一个可用区域的起始位置。
        /// </summary>
        /// <returns>该值为－1表示缓冲区空间已用完。为非负数时表现申请区域的起始位置的索引号</returns>
        public int CheckOut() {
            int offset;
            if (freeIndexPool.TryPop(out offset)) {
                int index = offset / size;
                if (bufferUsage[index])
                    throw new InvalidOperationException("指定的缓冲段已经被使用");
                bufferUsage[index] = true;
                return offset;
            }
            return -1;
        }

        /// <summary>
        /// 将可用区域起始位置偏移值再次登记为未使用
        /// </summary>
        /// <param name="offset"></param>
        /// <param name="onError"></param>
        public void CheckIn(int offset, bool onError) {
            int index = offset / size;

            if (bufferUsage[index]) {
                bufferUsage[index] = false;
                freeIndexPool.Push(offset);
                return;
            }
            if (!onError)
                throw new InvalidOperationException("非onError状态下，指定的缓冲区意外的重复回收登记");
        }
    }
}